﻿/*
//模拟过滤对象  
var filters = new Filter[]
{
    new Filter {Key = "NickName", Value = "dajun", Contract = LinkType.Like},
    new Filter {Key = "CurrentState", Value = "0", Contract = LinkType.Equal}
};
var users = _context.CF_Users.Where(filters);  //得到最终结果 */ 

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using JuCheap.Service.Model;

namespace JuCheap.Service.Extentions
{
    #region 扩展方法

    /// <summary>
    /// IQuaryable扩展
    /// </summary>
    public static class QuaryableExtention
    {
        /// <summary>
        /// IQuaryable扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="filters">过滤器</param>
        /// <returns></returns>
        public static IQueryable<T> Where<T>(this IQueryable<T> query, QueryFilter[] filters)
        {
            var param = DynamicLinq.CreateLambdaParam<T>("c");
            Expression body = Expression.Constant(true); //初始默认一个true
            if (filters != null&& filters.Any())
            {
                foreach (var filter in filters)
                {
                    switch (filter.Condition)
                    {
                        case ConditionType.And:
                            body = body.And(param.GenerateBody<T>(filter));
                            break;
                        case ConditionType.Or:
                            body = body.Or(param.GenerateBody<T>(filter));
                            break;
                        case ConditionType.AndAlso:
                            body = body.AndAlso(param.GenerateBody<T>(filter));
                            break;
                    }
                }
            }
            var lambda = param.GenerateTypeLambda<T>(body); //最终组成lambda  
            return query.Where(lambda);
        }
    }

    #endregion

    

    #region 动态Lambda表达式

    public static class DynamicLinq
    {
        /// <summary>  
        /// 创建lambda中的参数,即c=>c.xxx==xx 中的c  
        /// </summary>  
        public static ParameterExpression CreateLambdaParam<T>(string name)
        {
            return Expression.Parameter(typeof(T), name);
        }

        /// <summary>  
        /// 创建linq表达示的body部分,即c=>c.xxx==xx 中的c.xxx==xx  
        /// </summary>  
        public static Expression GenerateBody<T>(this ParameterExpression param, QueryFilter filterObj)
        {
            PropertyInfo property = typeof(T).GetProperty(filterObj.Key);

            //组装左边  
            Expression left = Expression.Property(param, property);
            //组装右边  
            Expression right = Expression.Constant(filterObj.Value, property.PropertyType);

            //todo: 下面根据需要扩展自己的比较  
            Expression filter = null;
            switch (filterObj.Contract)
            {
                case LinkType.Equal:
                    filter = Expression.Equal(left, right);
                    break;
                case LinkType.LessEqualThan:
                    filter = Expression.LessThanOrEqual(left, right);
                    break;

                case LinkType.LessThan:
                    filter = Expression.LessThan(left, right);
                    break;

                case LinkType.GraterThan:
                    filter = Expression.GreaterThan(left, right);
                    break;

                case LinkType.GraterEqualThan:
                    filter = Expression.GreaterThanOrEqual(left, right);
                    break;

                case LinkType.StartsWith:
                    filter = Expression.Call(left, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }),
                                 Expression.Constant(filterObj.Value));
                    break;

                case LinkType.EndsWith:
                    filter = Expression.Call(left, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }),
                                 Expression.Constant(filterObj.Value));
                    break;

                case LinkType.Like:
                    filter = Expression.Call(left, typeof(string).GetMethod("Contains", new[] { typeof(string) }),
                                 Expression.Constant(filterObj.Value));
                    break;
            }

            return filter;
        }

        /// <summary>  
        /// 创建完整的lambda,即c=>c.xxx==xx  
        /// </summary>  
        public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body)
        {
            return Expression.Lambda(body, param);
        }

        /// <summary>  
        /// 创建完整的lambda，为了兼容EF中的where语句  
        /// </summary>  
        public static Expression<Func<T, bool>> GenerateTypeLambda<T>(this ParameterExpression param, Expression body)
        {
            return (Expression<Func<T, bool>>)(param.GenerateLambda(body));
        }

        /// <summary>
        /// AndAlso
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="expressionRight"></param>
        /// <returns></returns>
        public static Expression AndAlso(this Expression expression, Expression expressionRight)
        {
            return Expression.AndAlso(expression, expressionRight);
        }

        /// <summary>
        /// Or
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="expressionRight"></param>
        /// <returns></returns>
        public static Expression Or(this Expression expression, Expression expressionRight)
        {
            return Expression.Or(expression, expressionRight);
        }

        /// <summary>
        /// And
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="expressionRight"></param>
        /// <returns></returns>
        public static Expression And(this Expression expression, Expression expressionRight)
        {
            return Expression.And(expression, expressionRight);
        }
    }

    #endregion
}
